// gcc -Wall -D__USE_INLINE__ -o registers registers.c 
// powerpc-linux-gnu-gcc -D__USE_INLINE__ -o registers registers.c

/*
 * Supported targets are 750, 7447, 440.
 * This module is as dynamic as possible, using live detection.
 */

#include <stdio.h>
#include <string.h>

#ifdef __amigaos4__
#include <proto/exec.h>
#endif

#ifdef __linux__
#include <fcntl.h>
#include <sys/ioctl.h>

//#define __KERNEL__
//#include <asm/reg.h>
#endif

#include "registers.h"

#ifdef __amigaos4__
typedef unsigned int (*movefrom_func)(void);
typedef void (*moveto_func)(unsigned int value);

extern unsigned mfspr_table_func(void);
extern unsigned mfdcr_table_func(void);

static unsigned int read_spr(reg)
{
	movefrom_func func;
	func = mfspr_table_func + 8 * reg;
	return func();
}

static unsigned int read_msr()
{
	return get_msr();
}

static unsigned int read_dcr(reg)
{
	movefrom_func func;
	func = mfdcr_table_func + 8 * reg;
	return func();
}
#else
static int fd;

static unsigned int read_spr(reg)
{
	return ioctl(fd, GET_SPR | reg, 0);
}

static unsigned int read_msr()
{
	return ioctl(fd, GET_MSR);
}

static unsigned int read_dcr(reg)
{
	return ioctl(fd, GET_DCR | reg, 0);
}
#endif

static pvr_t pvr;

void print_pvr(void)
{
	printf("PVR = 0x%08x\n", pvr.value);
	printf("   TYPE  = 0x%04x\n", pvr.type);
	printf("   TECH  = 0x%x\n", pvr.tech);
	printf("   MAJOR = 0x%x\n", pvr.major);
	printf("   MINOR = 0x%02x\n", pvr.minor);
}

void print_pir(pir_t pir)
{
	if (pvr.type == 0x7002) {
		printf("PIR     = Not implemented\n");
	} else {
		printf("PIR     = 0x%08x\n", pir);
	}
}

int is_booke(void)
{
	if ((pvr.type == 0x4222) || (pvr.type == 0x1302)){
		return 1;
	} else {
		return 0;
	}
}

void print_registers(void)
{
	unsigned int reg;
	pir_t pir;
	unsigned int bat;
	unsigned int ictrl;
	unsigned int ldstcr;
	unsigned int dabr;
	dbcr0_t dbcr0;
	dbcr1_t dbcr1;
	dbcr2_t dbcr2;
	dbsr_t dbsr;
	ccr0_t ccr0;
	ccr1_t ccr1;
	mmucr_t mmucr;
	thrm1_t thrm1;
	thrm3_t thrm3;

	/* Processor control */

	printf("\nProcessor control\n");

	// PVR (and check that the processor is supported)
	pvr.value = read_spr(SPR_PVR);
	if ((pvr.type == 0x4222) || (pvr.type == 0x1302) || (pvr.type == 0x8003) || (pvr.type == 0x8002) || (pvr.type == 0x7002)) {
		print_pvr();
	} else {
		printf("CPU not supported: PVR = 0x%08x\n", pvr.value);
		return;
	}

	// PIR
	if (pvr.type != 0x7002) {
		pir = read_spr(SPR_PIR);
	}
	print_pir(pir);

	// MSR
	reg = read_msr();
	if (is_booke()) {
		msr_booke_t msr_be;

		msr_be.value = reg;
		printf("MSR     = 0x%08x\n", msr_be.value);
		printf("   WE  = %d (Wait State Enable)\n", msr_be.we);
		printf("   CE  = %d (Critical Interrupt Enable)\n", msr_be.ce);
		printf("   EE  = %d (External Interrupt Enable)\n", msr_be.ee);
		printf("   PR  = %d (Problem State)\n", msr_be.pr);
		printf("   FP  = %d (Floating Point Available)\n", msr_be.fp);
		printf("   ME  = %d (Machine Check Enable)\n", msr_be.me);
		printf("   FE0 = %d (Floating Point Exception Mode 0)\n", msr_be.fe0);
		printf("   DWE = %d (Debug Wait Enable)\n", msr_be.dwe);
		printf("   DE  = %d (Debug Interrupt Enable)\n", msr_be.de);
		printf("   FE1 = %d (Floating Point Exception Mode 1)\n", msr_be.fe1);
		printf("   IS  = %d (Instruction Address Space)\n", msr_be.is);
		printf("   DS  = %d (Data Address Space)\n", msr_be.ds);
	} else {
		msr_t msr;

		msr.value = reg;
		printf("MSR     = 0x%08x\n", msr.value);
		printf("   VEC = %d (Vector Unit Available)\n", msr.vec);
		printf("   POW = %d (Power Management Enable)\n", msr.pow);
		printf("   ILE = %d (Exception Little Endian Mode)\n", msr.ile);
		printf("   EE  = %d (External Interrupt Enable)\n", msr.ee);
		printf("   PR  = %d (Privilege Mode)\n", msr.pr);
		printf("   FP  = %d (Floating Point Available)\n", msr.fp);
		printf("   ME  = %d (Machine Check Enable)\n", msr.me);
		printf("   FE0 = %d (Floating Point Exception Mode 0)\n", msr.fe0);
		printf("   SE  = %d (Single Trace Enable)\n", msr.se);
		printf("   BE  = %d (Branch Trace Enable)\n", msr.be);
		printf("   FE1 = %d (Floating Point Exception Mode 1)\n", msr.fe1);
		printf("   IP  = %d (Exception Prefix)\n", msr.ip);
		printf("   IR  = %d (Instruction Address Translation)\n", msr.ir);
		printf("   DR  = %d (Data Address Translation)\n", msr.dr);
		printf("   PMM = %d (Performance Monitor Marked Mode)\n", msr.pmm);
		printf("   RI  = %d (System Reset Or Machine Check Exception Recoverable)\n", msr.ri);
		printf("   LE  = %d (Little Endian Mode)\n", msr.le);
	}

	// BAT
	if (!is_booke()) {
		bat = read_spr(SPR_DBAT0U);
		printf("DBAT0U = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT0L);
		printf("DBAT0L = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT1U);
		printf("DBAT1U = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT1L);
		printf("DBAT1L = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT2U);
		printf("DBAT2U = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT2L);
		printf("DBAT2L = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT3U);
		printf("DBAT3U = 0x%08x\n", bat);
		bat = read_spr(SPR_DBAT3L);
		printf("DBAT3L = 0x%08x\n", bat);

		// TODO: Read additional DBAT and all IBAT registers as well
	} else {
		printf("DBATx   = Not implemented\n");
	}

	// SDR1
	if (!is_booke()) {
		reg = read_spr(SPR_SDR1);
		printf("SDR1    = 0x%08x\n", reg);
	}

	// MMUCR
	if (is_booke()) {
		mmucr.value = read_spr(SPR_MMUCR);
		printf("MMUCR    = 0x%08x\n", mmucr.value);
		printf("   SWOA    = %d (Store Without Allocate)\n", mmucr.swoa);
		printf("   U1TE    = %d (U1 Transient Enable)\n", mmucr.u1te);
		printf("   U2SWOAE = %d (U2 Store Without Allocate Enable)\n", mmucr.u2swoae);
		printf("   DULXE   = %d (Data Cache Unlock Exception Enable)\n", mmucr.dulxe);
		printf("   IULXE   = %d (Instruction Cache Unlock Exception Enable)\n", mmucr.iulxe);
		printf("   STS     = %d (Search Translation Space)\n", mmucr.sts);
		printf("   STID    = %d (Search Translation ID)\n", mmucr.stid);
	}

	// CCR0
	if (is_booke()) {
		ccr0.value = read_spr(SPR_CCR0);
		printf("CCR0    = 0x%08x\n", ccr0.value);
		printf("   PRE    = %d (Parity Recoverability Enable)\n", ccr0.pre);
		printf("   CPRE   = %d (Cache Read Parity Enable)\n", ccr0.cpre);
		printf("   DSTG   = %d (Disable Store Gathering)\n", ccr0.dstg);
		printf("   DAPUIB = %d (Disable APU Instruction Broadcast)\n", ccr0.dapuib);
		printf("   DTB    = %d (Disable Trace Broadcast)\n", ccr0.dtb);
		printf("   GICBT  = %d (Guaranteed Instruction Cache Block Touch)\n", ccr0.gicbt);
		printf("   GDCBT  = %d (Guaranteed Data Cache Block Touch)\n", ccr0.gdcbt);
		printf("   FLSTA  = %d (Force Load/Store Alignment)\n", ccr0.flsta);
	}

	// CCR1
	if (is_booke()) {
		ccr1.value = read_spr(SPR_CCR1);
		printf("CCR1    = 0x%08x\n", ccr1.value);
		printf("   ICDPEI = %d (Instruction Cache Data Parity Error Insert)\n", ccr1.icdpei);
		printf("   ICTPEI = %d (Instruction Cache Tag Parity Error Insert)\n", ccr1.ictpei);
		printf("   DCTPEI = %d (Data Cache Tag Parity Error Insert)\n", ccr1.dctpei);
		printf("   DCDPEI = %d (Data Cache Data Parity Error Insert)\n", ccr1.dcdpei);
		printf("   DCUPEI = %d (Data Cache U-bit Parity Error Insert)\n", ccr1.dcupei);
		printf("   DCMPEI = %d (Data Cache Modified-bit Parity Error Insert)\n", ccr1.dcmpei);
		printf("   FCOM   = %d (Force Cache Operation Miss)\n", ccr1.fcom);
		printf("   MMUPEI = %d (Memory Management Unit Parity Error Insert)\n", ccr1.mmupei);
		printf("   FFF    = %d (Force Full-line Flush)\n", ccr1.fff);
		printf("   TCS    = %d (Timer Clock Select)\n", ccr1.tcs);
	}

	// IVLIM
	if (is_booke()) {
		printf("IVLIM   = 0x%08x\n", read_spr(SPR_IVLIM));
	}

	// L2CR
	if (pvr.type == 0x7002) {
		l2cr_7002_t l2cr;

		l2cr.value = read_spr(SPR_L2CR);
		printf("L2CR    = 0x%08x\n", l2cr.value);
		printf("   L2E   = %d (L2 Enable)\n", l2cr.l2e);
		printf("   L2PE  = %d (L2 Data Parity Generation and Checking Enable)\n", l2cr.l2pe);
		printf("   L2SIZ = %d (L2 Size) (%d KB)\n", l2cr.l2siz, l2cr.l2siz * 256 );
		printf("   L2CLK = %d (L2 Clock Ratio)\n", l2cr.l2clk);
		printf("   L2RAM = %d (L2 RAM type)\n", l2cr.l2ram);
		printf("   L2DO  = %d (L2 Data Only)\n", l2cr.l2do);
		printf("   L2I   = %d (L2 Global Invalidate)\n", l2cr.l2i);
		printf("   L2CTL = %d (L2 RAM Control (ZZ Enable))\n", l2cr.l2ctl);
		printf("   L2WT  = %d (L2 Write-Through)\n", l2cr.l2wt);
		printf("   L2TS  = %d (L2 Test Support)\n", l2cr.l2do);
		printf("   L2OH  = %d (L2 Output Hold)\n", l2cr.l2i);
		printf("   L2SL  = %d (L2 DLL Slow)\n", l2cr.l2do);
		printf("   L2DL  = %d (L2 Differencial Clock)\n", l2cr.l2i);
		printf("   L2BYP = %d (L2 DLL Bypass)\n", l2cr.l2do);
		printf("   L2CS  = %d (L2 Clock Stop)\n", l2cr.l2i);
		printf("   L2DRO = %d (L2 DLL Rollover Checkstop Enable)\n", l2cr.l2do);
		printf("   L2CTR = %d (L2 DLL Counter Value (RO))\n", l2cr.l2i);
		printf("   L2IP  = %d (L2 Global Invalidate In Progress (RO))\n", l2cr.l2i);
	} else if ((pvr.type == 0x8003) || (pvr.type == 0x8002)) {
		l2cr_t l2cr;

		l2cr.value = read_spr(SPR_L2CR);
		printf("L2CR    = 0x%08x\n", l2cr.value);
		printf("   L2E   = %d ()\n", l2cr.l2e);
		printf("   L2PE  = %d ()\n", l2cr.l2pe);
		printf("   L2I   = %d ()\n", l2cr.l2i);
		printf("   L2IO  = %d ()\n", l2cr.l2io);
		printf("   L2DO  = %d ()\n", l2cr.l2do);
		printf("   L2REP = %d ()\n", l2cr.l2rep);
		printf("   L2HWF = %d ()\n", l2cr.l2hwf);
	}

	// ICTRL
	if ((pvr.type == 0x8003) || (pvr.type == 0x8002)) {
		ictrl = read_spr(SPR_ICTRL);
		printf("ICTRL   = 0x%08x\n", ictrl);
	} else {
		printf("ICTRL   = Not implemented\n");
	}

	// LDSTCR
	ldstcr = read_spr(SPR_LDSTCR);
	printf("LDSTCR  = 0x%08x\n", ldstcr);

	// HID0
	if (pvr.type == 0x7002) {
		hid0_7002_t hid0;

		hid0.value = read_spr(SPR_HID0);
		printf("HID0    = 0x%08x\n", hid0.value);
		printf("   EMCP  = %d (Enable MCP signal)\n", hid0.emcp);
		printf("   DBP   = %d (Enable 60x bus address and data parity generation)\n", hid0.dbp);
		printf("   EBA   = %d (Enable 60x bus address parity checking)\n", hid0.eba);
		printf("   EBC   = %d (Enable 60x bus data parity checking)\n", hid0.ebc);
		printf("   BCLK  = %d ()\n", hid0.bclk);
		printf("   ECLK  = %d ()\n", hid0.eclk);
		printf("   PAR   = %d (Disable precharge of ARTRY signal)\n", hid0.par);
		printf("   DOZE  = %d (Doze Mode Enable)\n", hid0.doze);
		printf("   NAP   = %d (Nap Mode Enable)\n", hid0.nap);
		printf("   SLEEP = %d (Sleep Mode Enable)\n", hid0.sleep);
		printf("   DPM   = %d (Dynamic Power Management enable)\n", hid0.dpm);
		printf("   NHR   = %d (Not Hard Reset)\n", hid0.nhr);
		printf("   ICE   = %d (Instruction Cache Enable)\n", hid0.ice);
		printf("   DCE   = %d (Data Cache Enable)\n", hid0.dce);
		printf("   ILOCK = %d (Instruction Cache Lock)\n", hid0.ilock);
		printf("   DLOCK = %d (Data Cache Lock)\n", hid0.dlock);
		printf("   ICFI  = %d (Instruction Cache Flash Invalidate)\n", hid0.icfi);
		printf("   DCFI  = %d (Data Cache Flash Invalidate)\n", hid0.dcfi);
		printf("   SPD   = %d (Speculative Data Cache and Instruction Cache Access Disable)\n", hid0.spd);
		printf("   IFEM  = %d (Enable M bit on bus for instruction fetches)\n", hid0.ifem);
		printf("   SGE   = %d (Store Gathering Enable)\n", hid0.sge);
		printf("   DCFA  = %d (Data Cache Flush Assist)\n", hid0.dcfa);
		printf("   BTIC  = %d (Branch Target Instruction Cache Enable)\n", hid0.btic);
		printf("   ABE   = %d (Address Broadcast Enable)\n", hid0.abe);
		printf("   BHT   = %d (Branch History Table Enable)\n", hid0.bht);
		printf("   NOPTI = %d (No-op the data cache touch instructions (dcbt, dcbst))\n", hid0.nopti);
	} else if ((pvr.type == 0x8003) || (pvr.type == 0x8002)) {
		hid0_t hid0;

		hid0.value = read_spr(SPR_HID0);
		printf("HID0    = 0x%08x\n", hid0.value);
		printf("   TBEN      = %d (Time Base Enable)\n", hid0.tben);
		printf("   STEN      = %d (Software Table search Enable)\n", hid0.sten);
		printf("   HI_BAT_EN = %d (Additional BATs enabled (reserved on MPC7451/MPC7441))\n", hid0.high_bat_en);
		printf("   NAP       = %d (Nap mode enable)\n", hid0.nap);
		printf("   SLEEP     = %d (Sleep mode enable)\n", hid0.sleep);
		printf("   DPM       = %d (Dynamic Power Management enable)\n", hid0.dpm);
		printf("   BHTCLR    = %d (Clear Branch History Table)\n", hid0.bhtclr);
		printf("   XAEN      = %d (Extended Addressing Enable)\n", hid0.xaen);
		printf("   NHR       = %d (Not Hard Reset)\n", hid0.nhr);
		printf("   ICE       = %d (Instruction Cache Enable)\n", hid0.ice);
		printf("   DCE       = %d (Data Cache Enable)\n", hid0.dce);
		printf("   ILOCK     = %d (Instruction Cache Lock)\n", hid0.ilock);
		printf("   DLOCK     = %d (Data Cache Lock)\n", hid0.dlock);
		printf("   ICFI      = %d (Instruction Cache Flash Invalidate)\n", hid0.icfi);
		printf("   DCFI      = %d (Data Cache Flash Invalidate)\n", hid0.dcfi);
		printf("   SPD       = %d (Speculative Data Cache and Instruction Cache Access Disable)\n", hid0.spd);
		printf("   XBSEN     = %d (Extended BAT block size enable (reserved on MPC7451/MPC7441))\n", hid0.xbsen);
		printf("   SGE       = %d (Store Gathering Enable)\n", hid0.sge);
		printf("   BTIC      = %d (Branch Target Instruction Cache Enable)\n", hid0.btic);
		printf("   LRSTK     = %d (Link Register Stack Enable / Reserved on 0x7002)\n", hid0.lrstk);
		printf("   FOLD/ABE  = %d (Branch Folding Enable) (Address Broadcast Enable on 0x7002)\n", hid0.fold);
		printf("   BHT       = %d (Branch History Table Enable)\n", hid0.bht);
		printf("   NOPDST    = %d (No-op dst, dstt, dstst and dststt) (Reserved on 0x7002)\n", hid0.nopdst);
		printf("   NOPTI     = %d (No-op the data cache touch instructions (dcbt, dcbst))\n", hid0.nopti);

		printf("HID1    = 0x%08x (4 MSB reflect PLL_CFG[0-3] signals\n", read_spr(SPR_HID1));
	}

	/* Exceptions handling */

	printf("\nExceptions handling\n");

	printf("SRR0    = 0x%08x\n", read_spr(SPR_SRR0));
	printf("SRR1    = 0x%08x\n", read_spr(SPR_SRR1));
	if (is_booke()) {
		printf("CSRR0   = 0x%08x\n", read_spr(SPR_CSRR0));
		printf("CSRR1   = 0x%08x\n", read_spr(SPR_CSRR1));
		printf("MCSRR0  = 0x%08x\n", read_spr(SPR_MCSRR0));
		printf("MCSRR1  = 0x%08x\n", read_spr(SPR_MCSRR1));

		printf("ESR     = 0x%08x\n", read_spr(SPR_ESR));
		printf("MCSR    = 0x%08x\n", read_spr(SPR_MCSR));
		printf("DEAR    = 0x%08x\n", read_spr(SPR_DEAR));

		printf("IVPR    = 0x%08x\n", read_spr(SPR_IVPR));
		printf("IVPR0   = 0x%08x (Critical Input)\n", read_spr(SPR_IVOR0));
		printf("IVPR1   = 0x%08x (Machine Check)\n", read_spr(SPR_IVOR1));
		printf("IVPR2   = 0x%08x (Data Storage)\n", read_spr(SPR_IVOR2));
		printf("IVPR3   = 0x%08x (Instruction Storage)\n", read_spr(SPR_IVOR3));
		printf("IVPR4   = 0x%08x (External Input)\n", read_spr(SPR_IVOR4));
		printf("IVPR5   = 0x%08x (Alignment)\n", read_spr(SPR_IVOR5));
		printf("IVPR6   = 0x%08x (Program)\n", read_spr(SPR_IVOR6));
		printf("IVPR7   = 0x%08x (Floating Point Unavailable)\n", read_spr(SPR_IVOR7));
		printf("IVPR8   = 0x%08x (System Call)\n", read_spr(SPR_IVOR8));
		printf("IVPR9   = 0x%08x (Auxiliary Processor Unavailable)\n", read_spr(SPR_IVOR9));
		printf("IVPR10  = 0x%08x (Decrementer)\n", read_spr(SPR_IVOR10));
		printf("IVPR11  = 0x%08x (Fixed Interval Timer)\n", read_spr(SPR_IVOR11));
		printf("IVPR12  = 0x%08x (Watchdog Timer)\n", read_spr(SPR_IVOR12));
		printf("IVPR13  = 0x%08x (Data TLB Error)\n", read_spr(SPR_IVOR13));
		printf("IVPR14  = 0x%08x (Instruction TLB Error)\n", read_spr(SPR_IVOR14));
		printf("IVPR15  = 0x%08x (Debug)\n", read_spr(SPR_IVOR15));
	}

	/* Debug */

	printf("\nDebug\n");

	// DABR
	if (!is_booke()) {
		dabr = read_spr(SPR_DABR);
		printf("DABR    = 0x%08x\n", dabr);
	}

	// DBCR0
	if (is_booke()) {
		dbcr0.value = read_spr(SPR_DBCR0);
		printf("DBCR0   = 0x%08x\n", dbcr0.value);
		printf("   EDM   = %d (External Debug Mode)\n", dbcr0.edm);
		printf("   IDM   = %d (Internal Debug Mode)\n", dbcr0.idm);
		printf("   RST   = %d (Reset)\n", dbcr0.rst);
		printf("   ICMP  = %d (Instruction Completion Debug Event)\n", dbcr0.icmp);
		printf("   BRT   = %d (Branch Taken Debug Event)\n", dbcr0.brt);
		printf("   IRPT  = %d (Interrupt Debug Event)\n", dbcr0.irpt);
		printf("   TRAP  = %d (Trap Debug Event)\n", dbcr0.trap);
		printf("   IAC1  = %d (Instruction Address Compare (IAC) 1 Debug Event)\n", dbcr0.iac1);
		printf("   IAC2  = %d (Instruction Address Compare (IAC) 2 Debug Event)\n", dbcr0.iac2);
		printf("   IAC3  = %d (Instruction Address Compare (IAC) 3 Debug Event)\n", dbcr0.iac3);
		printf("   IAC4  = %d (Instruction Address Compare (IAC) 4 Debug Event)\n", dbcr0.iac4);
		printf("   DAC1R = %d (Data Address Compare (DAC) 1 Read Debug Event)\n", dbcr0.dac1r);
		printf("   DAC1W = %d (Data Address Compare (DAC) 1 Write Debug Event)\n", dbcr0.dac1w);
		printf("   DAC2R = %d (Data Address Compare (DAC) 2 Read Debug Event)\n", dbcr0.dac2r);
		printf("   DAC2W = %d (Data Address Compare (DAC) 2 Write Debug Event)\n", dbcr0.dac2w);
		printf("   RET   = %d (Return Debug Event)\n", dbcr0.ret);
		printf("   FT    = %d (Freeze Timers On Debug Event)\n", dbcr0.ft);

		dbcr1.value = read_spr(SPR_DBCR1);
		printf("DBCR1   = 0x%08x\n", dbcr1.value);
		printf("   IAC1US  = %d (IAC 1 User/Supervisor)\n", dbcr1.iac1us);
		printf("   IAC1ER  = %d (IAC 1 Effective/Real)\n", dbcr1.iac1er);
		printf("   IAC2US  = %d (IAC 2 User/Supervisor)\n", dbcr1.iac2us);
		printf("   IAC2ER  = %d (IAC 2 Effective/Real)\n", dbcr1.iac2er);
		printf("   IAC12M  = %d (IAC 1/2 Mode)\n", dbcr1.iac12m);
		printf("   IAC12AT = %d (IAC 1/2 Auto-Toggle Enable)\n", dbcr1.iac12at);
		printf("   IAC3US  = %d (IAC 3 User/Supervisor)\n", dbcr1.iac3us);
		printf("   IAC3ER  = %d (IAC 3 Effective/Real)\n", dbcr1.iac3er);
		printf("   IAC4US  = %d (IAC 4 User/Supervisor)\n", dbcr1.iac4us);
		printf("   IAC4ER  = %d (IAC 4 Effective/Real)\n", dbcr1.iac4er);
		printf("   IAC34M  = %d (IAC 3/4 Mode)\n", dbcr1.iac34m);
		printf("   IAC34AT = %d (IAC 3/4 Auto-Toggle Enable)\n", dbcr1.iac34at);

		dbcr2.value = read_spr(SPR_DBCR1);
		printf("DBCR2   = 0x%08x\n", dbcr2.value);
		printf("   DAC1US  = %d (DAC 1 User/Supervisor)\n", dbcr2.dac1us);
		printf("   DAC1ER  = %d (DAC 1 Effective/Real)\n", dbcr2.dac1er);
		printf("   DAC2US  = %d (DAC 2 User/Supervisor)\n", dbcr2.dac2us);
		printf("   DAC2ER  = %d (DAC 2 Effective/Real)\n", dbcr2.dac2er);
		printf("   IAC12M  = %d (DAC 1/2 Mode)\n", dbcr2.dac12m);
		printf("   IAC12AT = %d (DAC 1/2 Asynchronous)\n", dbcr2.dac12a);
		printf("   DVC1M   = %d (DVC 1 Mode)\n", dbcr2.dvc1m);
		printf("   DVC2M   = %d (DVC 2 Mode)\n", dbcr2.dvc2m);
		printf("   DVC1BE  = %d (DVC 1 Byte Enables 0:3)\n", dbcr2.dvc1be);
		printf("   DVC2BE  = %d (DVC 2 Byte Enables 0:3)\n", dbcr2.dvc2be);

		dbsr.value = read_spr(SPR_DBSR);
		printf("DBSR    = 0x%08x\n", dbsr.value);
		printf("   IDE      = %d (Imprecise Debug Event)\n", dbsr.ide);
		printf("   UDE      = %d (Unconditional Debug Event)\n", dbsr.ude);
		printf("   MRR      = %d (Most Recent Reset)\n", dbsr.mrr);
		printf("   ICMP     = %d (Instruction Completion Debug Event)\n", dbsr.icmp);
		printf("   BRT      = %d (Branch Taken Debug Event)\n", dbsr.brt);
		printf("   IRPT     = %d (Interrupt Debug Event)\n", dbsr.irpt);
		printf("   TRAP     = %d (Trap Debug Event)\n", dbsr.trap);
		printf("   IAC1     = %d (IAC 1 Debug Event)\n", dbsr.iac1);
		printf("   IAC2     = %d (IAC 2 Debug Event)\n", dbsr.iac2);
		printf("   IAC3     = %d (IAC 3 Debug Event)\n", dbsr.iac3);
		printf("   IAC4     = %d (IAC 4 Debug Event)\n", dbsr.iac4);
		printf("   DAC1R    = %d (DAC 1 Read Debug Event)\n", dbsr.dac1r);
		printf("   DAC1W    = %d (DAC 1 Write Debug Event)\n", dbsr.dac1w);
		printf("   DAC2R    = %d (DAC 2 Read Debug Event)\n", dbsr.dac2r);
		printf("   DAC2W    = %d (DAC 2 Write Debug Event)\n", dbsr.dac2w);
		printf("   RET      = %d (Return  Debug Event)\n", dbsr.ret);
		printf("   IAC12ATS = %d (IAC 1/2 Auto-Toggle Status)\n", dbsr.iac12ats);
		printf("   IAC34ATS = %d (IAC 3/4 Auto-Toggle Status)\n", dbsr.iac34ats);

		printf("IAC1 = 0x%08x\n", read_spr(SPR_IAC1));
		printf("IAC2 = 0x%08x\n", read_spr(SPR_IAC2));
		printf("IAC3 = 0x%08x\n", read_spr(SPR_IAC3));
		printf("IAC4 = 0x%08x\n", read_spr(SPR_IAC4));
		printf("DAC1 = 0x%08x\n", read_spr(SPR_DAC1));
		printf("DAC2 = 0x%08x\n", read_spr(SPR_DAC2));
		printf("DVC1 = 0x%08x\n", read_spr(SPR_DVC1));
		printf("DVC2 = 0x%08x\n", read_spr(SPR_DVC2));
		printf("DBDR = 0x%08x\n", read_spr(SPR_DBDR));
	}

	/* Power and thermal management */

	printf("\nPower and thermal management\n");

	if (is_booke()) {
		printf("ICTC    = Not implemented\n");
		printf("THRMx   = Not implemented\n");
	} else {
		reg = read_spr(SPR_ICTC);
		printf("ICTC  = 0x%08x\n", reg);
		printf("   IF = %d (Instruction forwarding interval in clock cycles)\n", (reg >> 1) & 0xff);
		printf("   E  = %d (Cache Throttling Enable)\n", reg & 1);

		thrm1.value = read_spr(SPR_THRM1);
		printf("THRM1   = 0x%08x\n", thrm1.value);
		printf("   TIN    = %d (Thermal Management Interrupt Bit (RO))\n", thrm1.tin);
		printf("   TIV    = %d (Thermal Management Interrupt Valid (RO))\n", thrm1.tiv);
		printf("   THRESH = %d (Threshold value)\n", thrm1.threshold);
		printf("   TID    = %d (Thermal Management Interrupt Direction Bit)\n", thrm1.tid);
		printf("   TIE    = %d (Thermal Management Interrupt Enable)\n", thrm1.tie);
		printf("   V      = %d (Valid Bit (SPR contains a valid thresold))\n", thrm1.v);

		thrm1.value = read_spr(SPR_THRM2);
		printf("THRM2   = 0x%08x\n", thrm1.value);
		printf("   TIN    = %d (Thermal Management Interrupt Bit (RO))\n", thrm1.tin);
		printf("   TIV    = %d (Thermal Management Interrupt Valid (RO))\n", thrm1.tiv);
		printf("   THRESH = %d (Threshold value)\n", thrm1.threshold);
		printf("   TID    = %d (Thermal Management Interrupt Direction Bit)\n", thrm1.tid);
		printf("   TIE    = %d (Thermal Management Interrupt Enable)\n", thrm1.tie);
		printf("   V      = %d (Valid Bit (SPR contains a valid thresold))\n", thrm1.v);

		thrm3.value = read_spr(SPR_THRM3);
		printf("THRM3   = 0x%08x\n", thrm3.value);
		printf("   SITV = %d (Sample Interval Timer Value)\n", thrm3.sitv);
		printf("   E    = %d (Enable Thermal Sensor Compare Operation)\n", thrm3.e);
	}

	if (!is_booke()) {
		printf("CPMx   = Not implemented\n");
	} else {
		reg = read_dcr(DCR_CPM0_ER);
		printf("CPM0_ER = 0x%08x\n", reg);
		reg = read_dcr(DCR_CPM0_FR);
		printf("CPM0_FR = 0x%08x\n", reg);
		reg = read_dcr(DCR_CPM0_SR);
		printf("CPM0_SR = 0x%08x\n", reg);
	}

	/* Miscellaneous */

	printf("\nMiscellaneous\n");
	printf("DEC     = 0x%08x\n", read_spr(SPR_DEC));
	if (is_booke()) {
		printf("DECAR   = 0x%08x\n", read_spr(SPR_DECAR));
	}

	if (!is_booke()) {
		reg = read_spr(SPR_IABR);
		printf("IABR    = 0x%08x\n", reg);
		printf("   ADDR = 0x%08x\n", reg & ~3);
		printf("   BE   = %d (Breakpoint enabled)\n", (reg >> 1) & 1);
		printf("   TE   = %d (Translation enabled)\n", (reg & 1));

		printf("DABR    = 0x%08x\n", read_spr(SPR_DABR));
		printf("EAR     = 0x%08x\n", read_spr(SPR_EAR));
	}
}

/*
 * This main function will be pushed outside of this file
 */
int main(int argc, char **argv)
{
#ifdef __amigaos4__
	APTR user_state;

	user_state = SuperState();
	if (user_state) {
		print_registers();
		UserState(user_state);
	} else {
		printf("Failed to supervisor mode\n");
	}
#else
	fd = open("/dev/cpuregs", O_RDONLY, 0);
	if (fd == -1) {
		printf("Failed to open /dev/cpuregs (missing root access rights?)\n");
		return -1;
	} else {
		print_registers();
	}
#endif

	return 0;
}
